package ai.leinao.notify.core.utils;

import cn.hutool.core.bean.BeanUtil;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * 模板解析器
 * 模板字符串中的占位符（如 ${name}）替换为实际的值。
 *
 * @author zhong.wang
 * @date 2025/7/10
 */
public class TemplateParser {
    /**
     * 默认占位符起始符号
     */
    private static final char[] DEFAULT_PREPARE_START_SYMBOL = "${".toCharArray();

    /**
     * 默认占位符结束符号
     */
    private static final char[] DEFAULT_PREPARE_END_SYMBOL = "}".toCharArray();

    /**
     * 当前使用的起始符号
     */
    private char[] prepareStartSymbol;

    /**
     * 当前使用的结束符号
     */
    private char[] prepareEndSymbol;
    /**
     * 模板
     */
    private String template;

    /**
     * 参数
     */
    private Object parameter;

    /**
     * 模板字符串的字符数组表示
     */
    private char[] templateArray;

    /**
     * 模板字符串的索引
     */
    private int pos;

    /**
     * 当前字符
     */
    private char symbol;

    /**
     * 结果缓冲区
     */
    private char[] newArr;

    /**
     * 缓冲区已填充长度
     */
    private int len;

    /**
     * 占位符匹配标志
     */
    private byte prepareFlag;

    /**
     * 构造函数
     */
    public TemplateParser() {
        this.prepareStartSymbol = DEFAULT_PREPARE_START_SYMBOL;
        this.prepareEndSymbol = DEFAULT_PREPARE_END_SYMBOL;
        this.len = 0;
        this.prepareFlag = 0;
    }

    /**
     * 移动指针到下一个字符，并更新当前字符
     * @param chars
     * @param end
     */
    public void setParsed(char[] chars, int end) {
        for(int i = 0; i < end; ++i) {
            char aChar = chars[i];
            if (this.newArr.length <= this.len) {
                this.newArr = Arrays.copyOf(this.newArr, this.len + this.templateArray.length);
            }

            this.newArr[this.len++] = aChar;
        }

    }

    /**
     * 字符替换
     * @param chars
     */
    public void setParsed(char... chars) {
        this.setParsed(chars, chars.length);
    }

    /**
     * 初始化
     */
    private void init() {
        this.templateArray = this.template.toCharArray();
        this.pos = 0;
        this.newArr = new char[this.templateArray.length * 2];
    }

    /**
     * 判断是否正在解析占位符。
     * @return
     */
    private boolean isPreparing() {
        return this.prepareFlag > 0;
    }

    /**
     * 检测当前字符是否与起始符号匹配
     * @return
     */
    private boolean isPrepare() {
        if (this.prepareStartSymbol[this.prepareFlag] == this.symbol) {
            ++this.prepareFlag;
        }

        if (this.prepareFlag >= this.prepareStartSymbol.length) {
            this.prepareFlag = 0;
            return true;
        } else {
            return false;
        }
    }

    /**
     * 检测当前字符是否是结束符号之一
     * @return
     */
    private boolean isPrepareEnd() {
        char[] var1 = this.prepareEndSymbol;
        int var2 = var1.length;

        for(int var3 = 0; var3 < var2; ++var3) {
            char c = var1[var3];
            if (c == this.symbol) {
                return true;
            }
        }

        return false;
    }

    /**
     * 移动指针到下一个字符，并更新当前字符
     * @return
     */
    private boolean next() {
        this.symbol = this.templateArray[this.pos++];
        return this.pos < this.templateArray.length;
    }

    /**
     * 解析模板
     * @param propertyMapping
     * @return
     */
    public String parse(Function<String, String> propertyMapping) {
        this.init();
        boolean inPrepare = false;
        char[] expression = new char[128];
        int expressionPos = 0;

        while(true) {
            while(this.next()) {
                if (this.isPrepare()) {
                    inPrepare = true;
                } else if (inPrepare && this.isPrepareEnd()) {
                    inPrepare = false;
                    this.setParsed(((String)propertyMapping.apply(new String(expression, 0, expressionPos))).toCharArray());
                    expressionPos = 0;
                } else if (inPrepare) {
                    if (expression.length <= expressionPos) {
                        expression = Arrays.copyOf(expression, (int)((double)expression.length * 1.5));
                    }

                    expression[expressionPos++] = this.symbol;
                } else if (!this.isPreparing()) {
                    this.setParsed(this.symbol);
                }
            }

            if (this.isPrepareEnd() && expressionPos > 0) {
                this.setParsed(((String)propertyMapping.apply(new String(expression, 0, expressionPos))).toCharArray());
            } else {
                this.setParsed(this.symbol);
            }

            return new String(this.newArr, 0, this.len);
        }
    }

    /**
     * 解析模板
     * @param template
     * @param parameter
     * @return
     */
    public static String parse(String template, Object parameter) {
        return parse(template, (var) -> {
            try {
                return BeanUtil.getProperty(parameter, var);
            } catch (Exception var3) {
                return "";
            }
        });
    }

    /**
     * 解析模板
     * @param template
     * @param parameterGetter
     * @return
     */
    public static String parse(String template, Function<String, String> parameterGetter) {
        TemplateParser parser = new TemplateParser();
        parser.template = template;
        return parser.parse(parameterGetter);
    }

    /**
     * 获取准备开始符号
     * @return
     */
    public char[] getPrepareStartSymbol() {
        return this.prepareStartSymbol;
    }

    /**
     * 设置准备开始符号
     * @param prepareStartSymbol
     */
    public void setPrepareStartSymbol(final char[] prepareStartSymbol) {
        this.prepareStartSymbol = prepareStartSymbol;
    }

    /**
     * 获取准备结束符号
     * @return
     */
    public char[] getPrepareEndSymbol() {
        return this.prepareEndSymbol;
    }

    /**
     * 设置准备结束符号
     * @param prepareEndSymbol
     */
    public void setPrepareEndSymbol(final char[] prepareEndSymbol) {
        this.prepareEndSymbol = prepareEndSymbol;
    }

    /**
     * 获取模板
     * @return
     */
    public String getTemplate() {
        return this.template;
    }

    /**
     * 设置模板
     * @param template
     */
    public void setTemplate(final String template) {
        this.template = template;
    }

    /**
     * 获取参数
     * @return
     */
    public Object getParameter() {
        return this.parameter;
    }

    /**
     * 设置参数
     * @param parameter
     */
    public void setParameter(final Object parameter) {
        this.parameter = parameter;
    }


    public static void main(String[] args) {
        String template = "我的名字是${name},年龄为${age}";
        Map<String, Object> context = new HashMap<>();
        context.put("name", "dijia");
        context.put("age", 18);
        String parse = TemplateParser.parse(template, key -> {
            return context.get(key).toString();
        });

    }
}
